#include "config.h"

/* 1---dir, 0---file, -1---error */
int is_dir(const char *path)
{
	struct stat sb;
	if (lstat(path, &sb) == -1) {
		// fprintf(stderr, "config error: is_dir\n");
		return -1;
	}

	if (S_ISDIR(sb.st_mode)) {
		return 1;
	} else {
		return 0;
	}
}

char* cur_dir() {
	char dir[FILEPATH_SIZE];
	if (getcwd(dir, sizeof(dir)) == NULL) {
		fprintf(stderr, "config error: cur_dir()-->getcwd\n");
		return NULL;
	}

	const char *home = getenv("HOME");
    char *modified_dir;

    if (home && strstr(dir, home) == dir) { // If dir starts with HOME
        // Calculate the remaining part of the path after HOME
        const char *remaining_path = dir + strlen(home);
        // Create a new string for the modified directory
        modified_dir = malloc(strlen(remaining_path) + 2); // +2 for "~" and null terminator
        if (modified_dir) {
            sprintf(modified_dir, "~%s", remaining_path); // Replace HOME with ~
        }
    } else {
        modified_dir = strdup(dir); // Keep it as is
    }

    // Calculate final string length
    size_t len = strlen(CUR_DIR_STYLE) + strlen(modified_dir) + strlen(SYM_STYLE) + strlen(SYM) + 2*strlen(RESET) + 2; // 2 for " " and null terminator
    char *result = (char *) malloc(len * sizeof(char));
    if (result) {
        // Concatenate strings
        snprintf(result, len, "%s%s%s%s%s%s ", CUR_DIR_STYLE, modified_dir, RESET, SYM_STYLE, SYM, RESET);
		result[len] = '\0';
    } else {
		fprintf(stderr, "config error: cur_dir()-->malloc\n");
    	free(modified_dir); // Free the modified_dir after using it
		return NULL;
	}
    
    free(modified_dir); // Free the modified_dir after using it
    return result;
}

char *get_prompt()
{
    // Calculate final string length
    size_t len = strlen(PROMPT_STYLE) + strlen(PROMPT) + strlen(RESET) + 1; // 1 for null terminator
    char *result = malloc(len);

    if (result) {
        // Concatenate strings
        snprintf(result, len, "%s%s%s", PROMPT_STYLE, PROMPT, RESET);
    } else {
		fprintf(stderr, "config error: prompt()-->malloc\n");
		return NULL;
	}
    
    return result;
}

static int compare(const void *a, const void *b)
{
	return strcmp(((direntry_t *) a)->name, ((direntry_t *) b)->name);
}

direntry_t *get_list_files(const char *directory)
{
	DIR *dir = opendir(directory);
	if (!dir) {
		fprintf(stderr, "config error: general_list_files()-->opendir\n");
		return NULL;
	}

	direntry_t *de = (direntry_t *) malloc(sizeof(direntry_t) * (MAX_ENTRIES + 1)); 				// 1 for NULL 
								 // store the directory entries
	if (!de) {
		fprintf(stderr, "config error: general_list_files()-->malloc\n");
		free(de);
		return NULL;
	}
	int count = 0; 				// the number of directory entries
	struct dirent *entry;

	/* Read directory entries */
	while ((entry = readdir(dir)) != NULL) {
		struct stat st;
		char path[FILEPATH_SIZE];

		// complete file path
		snprintf(path, sizeof(path), "%s/%s", directory, entry->d_name);

		// store the result to dir_entry array
		if (lstat(path, &st) == 0) {
			int len = strlen(entry->d_name);
			if (len >= FILENAME_SIZE) len = FILENAME_SIZE - 1; // 1 for null terminator
			strncpy(de[count].name, entry->d_name, len); 
			de[count].name[len] = '\0';

			switch (st.st_mode & S_IFMT) {
				case S_IFDIR: 	de[count++].file_type = T_DIR; 	break;
				case S_IFREG: 	de[count++].file_type = T_REG; 	break;
				case S_IFIFO: 	de[count++].file_type = T_FIFO; break;
				case S_IFCHR: 	de[count++].file_type = T_CHR; 	break;
				case S_IFBLK: 	de[count++].file_type = T_BLK; 	break;
				case S_IFSOCK: 	de[count++].file_type = T_SOCK; break;
				case S_IFLNK: 	de[count++].file_type = T_LNK; 	break;
				default: 		de[count++].file_type = T_UNKW; break; 
			}
		}
	}
	de[count].name[0] = '\0';
	de[count].file_type = -1;
	closedir(dir);

	// sort by name
	qsort(de, count, sizeof(direntry_t), compare);

	return de;
}

void print_list_files(direntry_t *de, int list_hidden, const char *start)
{
	if (de == NULL) {
		fprintf(stderr, "config error: print_list_files");
		return;
	}

	printf("\n");
	for (int i = 0; de[i].file_type != -1; i++) {
		// print hidden file or not
		if (!list_hidden && strstr(de[i].name, ".") == de[i].name && strcmp(de[i].name, ".") != 0 && strcmp(de[i].name, "..") != 0) {
			continue;
		}

		// print file name begins with start
		if (start != NULL) {
			if (strstr(de[i].name, start) != de[i].name)
				continue;
		}

		// print result
		switch (de[i].file_type) {
			case T_DIR:
				printf("\t%sDIR:%s    %s%s%s\n", DIR_STYLE, RESET, DIR_C_STYLE, de[i].name, RESET);
				break;
			case T_REG:
				printf("\t%sREG:%s    %s%s%s\n", REG_STYLE, RESET, REG_C_STYLE, de[i].name, RESET);
				break;
			case T_LNK:
				printf("\t%sLNK:%s    %s%s%s\n", LNK_STYLE, RESET, LNK_C_STYLE, de[i].name, RESET);
				break;
			case T_CHR:
				printf("\t%sCHR:%s    %s%s%s\n", CHR_STYLE, RESET, CHR_C_STYLE, de[i].name, RESET);
				break;
			case T_BLK:
				printf("\t%sBLK:%s    %s%s%s\n", BLK_STYLE, RESET, BLK_C_STYLE, de[i].name, RESET);
				break;
			case T_FIFO:
				printf("\t%sFIFO:%s   %s%s%s\n", FIFO_STYLE, RESET, FIFO_C_STYLE, de[i].name, RESET);
				break;
			case T_SOCK:
				printf("\t%sSOCK:%s   %s%s%s\n", SOCK_STYLE, RESET, SOCK_C_STYLE, de[i].name, RESET);
				break;
			case T_UNKW:
				printf("\t%sUNKW:%s   %s%s%s\n", UNKW_STYLE, RESET, UNKW_C_STYLE, de[i].name, RESET);
				break;
			default:
				break;
		}
	}
	printf("\n");
}
